# coding=utf-8
import math

isD50 = False

matD50 = [ 0.436052025,
    0.385081593,
    0.143087414,
    0.222491598,
    0.716886060,
    0.060621486,
    0.013929122,
    0.097097002,
    0.714185470]

matD65 = [0.412453 ,0.357580, 0.180423,
       0.212671, 0.715160, 0.072169,
       0.019334, 0.119193, 0.950227]

wpD50 = [0.9642,1.0, 0.8249]            # D50白点；
wpD65 = [0.950456, 1.0, 1.0858754]           # D65白点；

def gamma(x):
    if x > 0.04045:
        return math.pow((x + 0.055)/1.055, 2.4)
    else:
        return x/12.92

def rgb2xyz(color):
    r, g, b = color
    tmpRgb = (gamma(r/255.0), gamma(g/255.0), gamma(b/255.0))
    tmpXyz = [0] * 3
    if isD50:
        for i in range(3):
            tmpXyz[i] = matD50[i * 3] * tmpRgb[0] + matD50[i * 3 + 1] * tmpRgb[1] + matD50[i * 3 + 2] * tmpRgb[2]
    else:
        for i in range(3):
            tmpXyz[i] = matD65[i * 3] * tmpRgb[0] + matD65[i * 3 + 1] * tmpRgb[1] + matD65[i * 3 + 2] * tmpRgb[2]

    return tuple(tmpXyz)


def xyz2lab(color):
    x, y, z = color
    if isD50:
        xn = wpD50[0]
        yn = wpD50[1]
        zn = wpD50[2]
    else:
        xn = wpD65[0]
        yn = wpD65[1]
        zn = wpD65[2]

    param_13 = 1.0 / 3.0
    param_16116 = 16.0 / 116.0
    x /= xn
    y /= yn
    z /= zn

    if y > 0.008856:
        fy = y ** param_13
        l = 116.0 * fy - 16
    else:
        fy = 7.787 * y + param_16116
        l = 903.3 * y

    l = max(0, l)
    if x > 0.008856:
        fx = x ** param_13
    else:
        fx = 7.787 * x + param_16116
    if z > 0.008856:
        fz = z ** param_13
    else:
        fz = 7.787 * z + param_16116

    a = 500.0 * (fx - fy)
    b = 200.0 * (fy - fz)

    return (l, a, b)


def lab2lch(color):
    l, a, b = color
    c = math.sqrt(a ** 2 + b ** 2)
    h = (math.atan2(b, a) * 180 / math.pi + 360) % 360
    h = h * math.pi / 180

    return (l, c, h)


def rgb2lch(color):
    xyz_color = rgb2xyz(color)
    lab_color = xyz2lab(xyz_color)
    lch_color = lab2lch(lab_color)

    return lch_color


# ------------------------------------------------------
def lch2lab(color):
    l, c, h = color
    h = h * math.pi / 180
    a = c * math.cos(h)
    b = c * math.sin(h)

    return (l, a, b)


def xyz2rgb(color):
    x, y, z = color
    if isD50:
        RR = 3.1338561 * x - 1.6168667 * y - 0.4906146 * z
        GG = -0.9787684 * x + 1.9161415 * y + 0.0334540 * z
        BB =  0.0719453 * x - 0.2289914 * y + 1.4052427 * z
    else:
        RR = 3.240479 * x - 1.537150 * y - 0.498535 * z
        GG = -0.969256 * x + 1.875992 * y + 0.041556 * z
        BB = 0.055648 * x - 0.204043 * y + 1.057311 * z

    RR = RR/100.0
    GG = GG/100.0
    BB = BB/100.0

    if RR < 0.00313:
        RR = RR * 12.92
    else:
        RR = math.pow(RR, 1.0/2.4)* 1.055 - 0.055

    if GG < 0.00313:
        GG = GG * 12.92
    else:
        GG = math.pow(GG , 1.0/2.4)* 1.055 - 0.055

    if BB < 0.00313:
        BB = BB * 12.92
    else:
        BB = math.pow(BB , 1.0/2.4)* 1.055 - 0.055

    RR = RR * 255
    GG = GG * 255
    BB = BB * 255

    if RR < 0:
        RR = 0
    elif RR > 255:
        RR = 255

    if GG < 0:
        GG = 0
    elif GG > 255:
        GG = 255

    if BB < 0:
        BB = 0
    elif BB > 255:
        BB = 255

    return (RR, GG, BB)


def lab2xyz(color):
    param_16116 = 16.0 / 116.0

    l, a, b = color
    fy = (l + 16) / 116
    if fy > 0.206893:
        y = fy ** 3
    else:
        y = (fy - param_16116) / 7.78
    fx = a / 500 + fy
    if fx > 0.206893:
        x = fx ** 3
    else:
        x = (fx - param_16116) / 7.787
    fz = fy - b / 200
    if fz > 0.206893:
        z = fz ** 3
    else:
        z = (fz - param_16116) / 7.787

    if isD50:
        x *= wpD50[0]
        y *= wpD50[1]
        z *= wpD50[2]
    else:
        x *= wpD65[0]
        y *= wpD65[1]
        z *= wpD65[2]

    return (x, y, z)


def lch2rgb(color):
    lab_color = lch2lab(color)
    xyz_color = lab2xyz(lab_color)
    rgb_color = xyz2rgb(xyz_color)
    return rgb_color


if __name__ == "__main__":
    color = [202, 21, 21]
    xyz = rgb2xyz(color)
    #xyz = [d * 100 for d in xyz]
    lab = xyz2lab(xyz)
    # color = [48.84, -14.31, -58.16]
    # # color = [d/100 for d in color]
    # xyz = lab2xyz(color)
    # xyz = [d * 100 for d in xyz]
    # rgb = xyz2rgb(xyz)
    print(lab)